package com.pig4cloud.pig.auth.support.base;

import lombok.Getter;
import org.springframework.lang.Nullable;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.util.Assert;

import java.io.Serial;
import java.util.*;

/**
 * OAuth2 资源所有者基础认证令牌抽象类
 * <p>
 * 此类为所有自定义 OAuth2 认证模式提供基础实现。
 * 继承自 Spring Security 的 AbstractAuthenticationToken，
 * 并添加了 OAuth2 相关的属性和方法。
 * 
 * 核心属性：
 * - authorizationGrantType: 授权类型（如 password、sms 等）
 * - clientPrincipal: 客户端认证信息
 * - scopes: 授权范围
 * - additionalParameters: 额外参数（如验证码、设备信息等）
 *
 * @author lengleng
 * @date 2025/05/30
 */
public abstract class OAuth2ResourceOwnerBaseAuthenticationToken extends AbstractAuthenticationToken {

	@Serial
	private static final long serialVersionUID = 1L;

	/**
	 * 授权类型
	 * 定义了使用何种方式进行认证（password、sms、social 等）
	 */
	@Getter
	private final AuthorizationGrantType authorizationGrantType;

	/**
	 * 客户端认证主体
	 * 包含已经认证的客户端信息（clientId、clientSecret 等）
	 */
	@Getter
	private final Authentication clientPrincipal;

	/**
	 * 授权范围集合
	 * 定义了此次认证请求的访问范围
	 */
	@Getter
	private final Set<String> scopes;

	/**
	 * 额外参数映射
	 * 用于存储认证过程中的额外信息，如：
	 * - 验证码
	 * - 设备 ID
	 * - 登录 IP
	 * - 其他自定义参数
	 */
	@Getter
	private final Map<String, Object> additionalParameters;

	/**
	 * 构造函数
	 * 
	 * @param authorizationGrantType 授权类型，不能为空
	 * @param clientPrincipal 客户端认证主体，不能为空
	 * @param scopes 授权范围，可以为空
	 * @param additionalParameters 额外参数，可以为空
	 */
	public OAuth2ResourceOwnerBaseAuthenticationToken(AuthorizationGrantType authorizationGrantType,
			Authentication clientPrincipal, @Nullable Set<String> scopes,
			@Nullable Map<String, Object> additionalParameters) {
		super(Collections.emptyList());  // 初始化时没有权限信息
		Assert.notNull(authorizationGrantType, "authorizationGrantType cannot be null");
		Assert.notNull(clientPrincipal, "clientPrincipal cannot be null");
		this.authorizationGrantType = authorizationGrantType;
		this.clientPrincipal = clientPrincipal;
		// 使用不可变集合保证线程安全
		this.scopes = Collections.unmodifiableSet(scopes != null ? new HashSet<>(scopes) : Collections.emptySet());
		this.additionalParameters = Collections.unmodifiableMap(
				additionalParameters != null ? new HashMap<>(additionalParameters) : Collections.emptyMap());
	}

	/**
	 * 获取凭证信息
	 * <p>
	 * 在 OAuth2 扩展模式中，一般不需要密码作为凭证。
	 * 凭证信息可能是验证码、第三方令牌等，
	 * 具体由子类根据业务需求决定。
	 * 
	 * @return 默认返回空字符串
	 */
	@Override
	public Object getCredentials() {
		return "";
	}

	/**
	 * 获取认证主体
	 * <p>
	 * 返回客户端的认证信息。
	 * 在认证成功后，这里将包含用户的详细信息。
	 * 
	 * @return 客户端认证主体
	 */
	@Override
	public Object getPrincipal() {
		return this.clientPrincipal;
	}

}
